import java.util.ArrayList;
import java.util.Collections;


public class Hand {
    ArrayList<Card> cards;
    Set set;

    public Hand(ArrayList<Card> cards)
    {
        Collections.sort(cards);
        this.cards = cards;
    }

    public Card pickCard(int index)
    {
        return cards.get(index);
    }

    public void addCard(Card c)
    {
        if(cards.size()<5)
        {
            cards.add(c);
        }
        Collections.sort(cards);
    }

    public void delCards(ArrayList<Card> CardsToRemove)
    {
        cards.removeAll(CardsToRemove);
    }

    public String pickSet()
    {
        settleSet();
        return set.name();
    }
    public void settleSet()
    {
        if(ifFlush())
        {
            set = Set.Straight_Flush;
        }
        else if(ifFOAK())
        {
            set = Set.Four_Of_A_Kind;
        }
        else if(ifFull_House())
        {
            set = Set.Full_House;
        }
        else if(ifColour())
        {
            set = Set.Flush;
        }
        else if(ifStraight())
        {
            set = Set.Straight;
        }
        else if(ifThree())
        {
            set = Set.Three_Of_A_Kind;
        }
        else if(ifTwoPairs())
        {
            set = Set.Two_Pairs;
        }
        else if(ifPair())
        {
            set = Set.A_Pair;
        }
        else
        {
            set = Set.High_Card;
        }
    }



    private boolean ifFlush()
    {
        return ifStraight() && ifColour();
    }

    private boolean ifStraight()
    {
        ArrayList<Card> Handcopy = (ArrayList<Card>) cards.clone();

        Card first = Handcopy.get(0);
        Card last = Handcopy.get(4);

        return (Math.abs((last.rank.getValue() - first.rank.getValue())) == 4) && !ifPair();
    }

    private boolean ifColour()
    {
        ArrayList<Card> Handcopy = (ArrayList<Card>) cards.clone();
        boolean sameColours = true;
        Card first = Handcopy.remove(0);

        for(Card card : Handcopy)
        {
            if( !card.colour.equals(first.colour))
            {
                sameColours = false;
                break;
            }

        }

        return sameColours;
    }

    private boolean ifFOAK()
    {
        return compareCardRanks(0,3) || compareCardRanks(1,4);
    }

    private boolean compareCardRanks(int indexOfFirst, int indexOfSecond)
    {
        return  cards.get(indexOfFirst).rank.equals(cards.get(indexOfSecond).rank);
    }

    private ArrayList<Card> returnSetOfFOAK()
    {
        ArrayList<Card> set = new ArrayList<>();

        if(compareCardRanks(0,3))
        {
            set.add(cards.get(0));
            set.add(cards.get(1));
            set.add(cards.get(2));
            set.add(cards.get(3));
        }
        else if(compareCardRanks(1,4))
        {
            set.add(cards.get(1));
            set.add(cards.get(2));
            set.add(cards.get(3));
            set.add(cards.get(4));
        }
        return set;
    }

    private boolean ifFull_House()
    {

        return compareCardRanks(0,1) && compareCardRanks(2,4)
               || compareCardRanks(0,2) && compareCardRanks(3,4);
    }

    private boolean ifThree()
    {
        return compareCardRanks(0,2) || compareCardRanks(1,3) || compareCardRanks(2,4);
    }

    private ArrayList<Card> returnSetOfThree()
    {
        ArrayList<Card> set = new ArrayList<>();

        if (compareCardRanks(0,2))
        {
            set.add(cards.get(0));
            set.add(cards.get(1));
            set.add(cards.get(2));
        }
        else if(compareCardRanks(1,3))
        {
            set.add(cards.get(1));
            set.add(cards.get(2));
            set.add(cards.get(3));
        }
        else if(compareCardRanks(2,4))
        {
            set.add(cards.get(2));
            set.add(cards.get(3));
            set.add(cards.get(4));
        }

        return set;
    }

    private boolean ifTwoPairs()
    {
        return compareCardRanks(0,1) && compareCardRanks(2,3)
                || compareCardRanks(0,1) && compareCardRanks(3,4)
                || compareCardRanks(1,2) && compareCardRanks(3,4);
    }

    private ArrayList<Card> returnSetOfTwoPairs()
    {

        ArrayList<Card> set = new ArrayList<>();
        if( compareCardRanks(0,1) && compareCardRanks(2,3))
        {
            ArrayList<Card> Cardcopy = (ArrayList<Card>)cards.clone();
            set.addAll(Cardcopy);
            set.remove(4);
        }
        else if(compareCardRanks(0,1) && compareCardRanks(3,4))
        {
            set.add(cards.get(0));
            set.add(cards.get(1));
            set.add(cards.get(3));
            set.add(cards.get(4));
        }
        else if(compareCardRanks(1,2) && compareCardRanks(3,4))
        {
            ArrayList<Card> Cardcopy = (ArrayList<Card>)cards.clone();
            set.addAll(Cardcopy);
            set.remove(0);
        }

        return set;
    }

    private boolean ifPair()
    {
        return compareCardRanks(0,1) || compareCardRanks(1,2) || compareCardRanks(2,3) || compareCardRanks(3,4);
    }

    private ArrayList<Card> returnSetOfPair()
    {
        ArrayList<Card> set = new ArrayList<>();


        if( compareCardRanks(0,1))
        {
            set.add(cards.get(0));
            set.add(cards.get(1));
        }
        else if( compareCardRanks(1,2))
        {
            set.add(cards.get(1));
            set.add(cards.get(2));
        }
        else if( compareCardRanks(2,3))
        {
            set.add(cards.get(2));
            set.add(cards.get(3));
        }
        else if( compareCardRanks(3,4))
        {
            set.add(cards.get(3));
            set.add(cards.get(4));
        }

        return set;
    }

    private int finalHandSum()
    {
        return Cardsum(cards);
    }

    private int Cardsum(ArrayList<Card> cards)
    {
        int sum = 0;
        for(Card c : cards)
        {
            sum += c.rank.ordinal();
        }
        return sum;
    }
    public int compareTo(Hand secondHand)
    {
        settleSet();
        secondHand.settleSet();
        int comparingRes = 0;


        if(set.compareTo(secondHand.set) == 0)
        {
            if(set.equals(Set.Straight_Flush))
            {
                comparingRes = cards.get(4).compareTo(secondHand.cards.get(4));
            }
            else if(set.equals(Set.Four_Of_A_Kind))
            {
            	comparingRes = returnSetOfFOAK().get(3).compareTo(secondHand.returnSetOfFOAK().get(3));
            }
            else if(set.equals(Set.Full_House))
            {
                if (returnSetOfThree().get(0).compareTo(secondHand.returnSetOfThree().get(0)) == 0)
                {
                    ArrayList<Card> Cardscopy = (ArrayList<Card>)cards.clone();
                    Cardscopy.removeAll(returnSetOfThree());

                    ArrayList<Card> CardcopyOfSecondHand = (ArrayList<Card>)secondHand.cards.clone();
                    CardcopyOfSecondHand.removeAll(secondHand.returnSetOfThree());

                    comparingRes = Cardscopy.get(0).compareTo(CardcopyOfSecondHand.get(0));
                }
                else
                {
                	comparingRes = returnSetOfThree().get(0).compareTo(secondHand.returnSetOfThree().get(0));
                }
            }
            else if(set.equals(Set.Flush))
            {
                if(finalHandSum() > secondHand.finalHandSum())
                {
                	comparingRes = 1;
                }
                else
                {
                	comparingRes = -1;
                }
            }
            else if(set.equals(Set.Straight))
            {
            	comparingRes = cards.get(0).compareTo(secondHand.cards.get(0));
            }
            else if(set.equals(Set.Three_Of_A_Kind))
            {
            	comparingRes = returnSetOfThree().get(0).compareTo(secondHand.returnSetOfThree().get(0));
            }
            else if(set.equals(Set.Two_Pairs))
            {
                if(Cardsum(returnSetOfTwoPairs()) == secondHand.Cardsum(secondHand.returnSetOfTwoPairs()))
                {
                    ArrayList<Card> Cardscopy = (ArrayList<Card>)cards.clone();
                    Cardscopy.removeAll(returnSetOfTwoPairs());

                    ArrayList<Card> CardcopyOfSecondHand = (ArrayList<Card>)secondHand.cards.clone();
                    CardcopyOfSecondHand.removeAll(secondHand.returnSetOfTwoPairs());
                    comparingRes = Cardscopy.get(0).compareTo(CardcopyOfSecondHand.get(0));
                }
            }
            else if(set.equals(Set.A_Pair))
            {
            	comparingRes = returnSetOfPair().get(0).compareTo(secondHand.returnSetOfPair().get(0));
                if(comparingRes == 0)
                {
                	comparingRes = cards.get(4).compareTo(secondHand.cards.get(4));
                }
            }
            else if(set.equals(Set.High_Card))
            {
            	comparingRes = cards.get(4).compareTo(secondHand.cards.get(4));
            }
        }
        else
        {
        	comparingRes = set.compareTo(secondHand.set);
        }

        return comparingRes;
    }

    public String toString() {
        return Card.downCardList(cards);
    }
}
